#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdlib.h>
#include <string.h>

typedef void (type_handler)(void);
typedef void (*type_pointer_handler)(void);

typedef struct _timer_handler* p_timer_handler;
typedef struct _timer_handler  timer_handler;

struct _timer_handler
{
 unsigned char  number;
 short count;
 short top;
 type_pointer_handler handler;
 p_timer_handler next;
};

typedef struct _list_handler* p_list_handler;
typedef struct _list_handler  list_handler;

struct _list_handler
{
	p_timer_handler head;
	p_timer_handler tail;
};

void Init_Timer0(void)
{
 OCR0=127;//125 for 8 MHz
 TCCR0|=1<<WGM01|1<<CS01|1<<CS00;
 TIMSK|=1<<OCIE0;
};


void handler_default(void)
{
 asm("nop");
};

void Init_handler(p_list_handler p)
{
	p_timer_handler tmp;
	
	tmp=(p_timer_handler)calloc(sizeof(timer_handler),1);
	cli();
		tmp->number=0;
		tmp->top=10;
		tmp->count=0;
		tmp->handler=handler_default;
		tmp->next=NULL;
	p->head=tmp;
	p->tail=tmp;
	sei();
};


void add_handler(p_list_handler p,short _top,type_handler f,unsigned char _number)
{
	p_timer_handler tmp;
	
	cli();
		tmp=(p_timer_handler)calloc(sizeof(timer_handler),1);
			tmp->number=_number;
			tmp->top=_top;
			tmp->count=0;
			tmp->handler=f;
			tmp->next=NULL;
		p->tail->next=tmp;
		p->tail=tmp;
	sei();
};


void reset_timer_handler(p_list_handler p,unsigned char _number)
{
p_timer_handler tmp;	

	tmp=p->head;

	while(tmp!=NULL)
	{
	 if (tmp->number==_number) 
	 { 
	  tmp->count=0;
	 }
	 tmp=tmp->next;
	};
};























typedef struct _list_button* p_list_button;
typedef struct _list_button  list_button;


typedef struct _conf_button* p_conf_button;
typedef struct _conf_button  conf_button;

typedef struct _button  button;

struct _button
{
unsigned char pin:6;
unsigned char press:1;
unsigned char event:1;
};

struct _conf_button
{
 unsigned  char number;

 short 		count;
 short*		port;
 button 	btn;

 type_pointer_handler handler_down;
 type_pointer_handler handler_up;
 type_pointer_handler handler_press;

 p_conf_button next;
};

struct _list_button
{
 p_conf_button head;
 p_conf_button tail;
};

void add_button(p_list_button p,unsigned  char _number,short* _port,unsigned char _pin,type_pointer_handler _handler_down,type_pointer_handler _handler_press,type_pointer_handler _handler_up)
{
	p_conf_button tmp;
	
	if (p->head!=NULL)
	{
		cli();
			tmp=(p_conf_button)calloc(sizeof(conf_button),1);
				tmp->number=_number;
				tmp->port=_port;
				tmp->count=0;
				tmp->btn.event=0;
				tmp->btn.press=0;
				tmp->btn.pin=_pin;
				tmp->handler_up=_handler_up;
				tmp->handler_down=_handler_down;
				tmp->handler_press=_handler_press;
				tmp->next=NULL;
				p->tail->next=tmp;
				p->tail=tmp;
		sei();
	} else
	{
		tmp=(p_conf_button)calloc(sizeof(conf_button),1);
		cli();
			tmp->port=_port;
			tmp->count=0;
			tmp->btn.event=0;
			tmp->btn.press=0;
			tmp->btn.pin=_pin;
			tmp->handler_up=_handler_up;
			tmp->handler_down=_handler_down;
			tmp->handler_press=_handler_press;
			tmp->next=NULL;
			p->head=tmp;
			p->tail=tmp;
		sei();
	};
}


void check_buttons(p_list_button p)
{
	p_conf_button tmp;

	tmp=p->head;
	while(tmp!=NULL)
	{
		if (*((unsigned char*)((unsigned char*)tmp->port))&(1<<tmp->btn.pin))
		{			
		  if (tmp->count>10)	
		  {
			if (tmp->btn.press==0)
			{
				tmp->btn.press=1;
				tmp->btn.event=1;
				if (tmp->handler_down!=NULL) tmp->handler_down();
			}; 
			if (tmp->btn.press==1)
			{
			if (tmp->handler_press!=NULL) tmp->handler_press();				
			};
		  } else tmp->count++;
		} 
		else
		{
		  if (tmp->count==0)
		   {
			 if (tmp->btn.press==1) 
			 {
			  tmp->btn.press=0;
			  if (tmp->handler_up!=NULL) tmp->handler_up();
			 };
		   } else tmp->count--;
		};
	  tmp=tmp->next;
	};
};


unsigned char get_event_button(p_list_button p,unsigned  char _number)
{
p_conf_button tmp;	

	tmp=p->head;

	while(tmp!=NULL)
	{
	 if (tmp->number==_number) 
	 { 
		if (tmp->btn.event==1)
		{
		 tmp->btn.event=0;
		 return 1;
		} else return 0;
		
	 }
	 tmp=tmp->next;
	};
	return 0;
};

unsigned char get_press_button(p_list_button p,unsigned  char _number)
{
p_conf_button tmp;	

	tmp=p->head;

	while(tmp!=NULL)
	{
	 if (tmp->number==_number) 
	 { 
		if (tmp->btn.press==1) return 1; else return 0;

	 }
	 tmp=tmp->next;
	};


	return 0;
};


list_handler main_timer0={NULL,NULL};
list_button  main_button={NULL,NULL};

void check_button(void)
{	
	check_buttons(&main_button);
};

void power_off(void)
{	
	PORTA&=~(1<<PA3);
};

void button1_down(void)
{
PORTA|=1<<PA0;	
	reset_timer_handler(&main_timer0,2);
	PORTA|=(1<<PA3);
}

void button1_press(void)
{
	PORTA=(1<<PA1);
	reset_timer_handler(&main_timer0,2);
	PORTA|=(1<<PA3);
}

void button1_up(void)
{
	PORTA&=~(1<<PA0);	
};

int main(void)
{

 PORTC|=1<<PC6;
 DDRA|=1<<PA0|1<<PA1|1<<PA2|1<<PA3;

 Init_handler(&main_timer0);
 add_handler(&main_timer0,1,check_button,1);
 add_handler(&main_timer0,10000,power_off,2);

 add_button(&main_button,0,&PINC,7,NULL,NULL,NULL);
 add_button(&main_button,1,&PINC,6,button1_down,button1_press,button1_up);
 add_button(&main_button,2,&PINC,5,NULL,NULL,NULL);
 Init_Timer0();
 sei();
 

 while(1)
 {
	asm("nop");
 };
 return 0;
}



SIGNAL(TIMER0_COMP_vect)
{
p_timer_handler tmp;	

	tmp=main_timer0.head;

	while(tmp!=NULL)
	{
	 if (tmp->count==tmp->top) 
		 {
		  tmp->count=0;
		  tmp->handler();

		 } else tmp->count++;
	 tmp=tmp->next;
	}

};
